#include <stdio.h>

#define MaxSize 100//矩阵中非零元素最多个数
#define N 4			//稀疏矩阵行数
#define M 4			//稀疏矩阵列数
typedef int elem;
typedef struct
{
	int r;			//行数
	int c;			//列数
	elem d;			//数据元素
}TupNode;			//三元组定义

typedef struct
{
	int row;				//行数值
	int cols;				//列数值
	int nums;				//非零元素个数
	TupNode data[MaxSize];	//存放数组
}TSMatrix;					//三元组顺序表定义

//生成稀疏矩阵A三元组
void CreatMat(TSMatrix &t, elem A[N][M])
{
	int i, j;
	t.row = N;			//总行数
	t.cols = M;			//总列数
	t.nums = 0;			//总非零元素数，初始为零
	for(i = 0; i < N; i++)//遍历数组A
	{
		for(j = 0; j < M; j++)
		{
			if(A[i][j] != 0)				//判断是否为非零元素
			{
				t.data[t.nums].r = i;		//记录非零元素所在的行数
				t.data[t.nums].c = j;		//记录非零元素所在的列数
				t.data[t.nums].d = A[i][j];	//记录非零元素值
				t.nums++;					//非零元素个数加一
			}
		}
	}
} 

//输出三元组
void DipMat(TSMatrix t)
{
	int i;
	if(t.nums <= 0)//判断是否有非零元素
		return;
	printf("\t%d\t%d\t%d\n",t.row, t.cols, t.nums);
	printf("-------------------------------------\n");
	for(i = 0; i < t.nums; i++)
		printf("\t%d\t%d\t%d\n",t.data[i].r, t.data[i].c, t.data[i].d);
}

//三元组转置
void TranTat(TSMatrix t, TSMatrix &tb)
{
	int p, q = 0, v;		//q为ta.data的下标,v进行计数，p为t.data的下标
	tb.row = t.cols;		//总行数和总列数互换
	tb.cols = t.row;
	tb.nums = t.nums;		//非零元素个数
	if(t.nums != 0)			//当存在非零元素时进行转置
	{
		for(v = 0; v < t.cols; v++)//t列数为ta的行数
		{
			for(p = 0; p < t.nums; p++)
				if(t.data[p].c == v)
				{
					tb.data[q].r = t.data[p].c;//行列互换
					tb.data[q].c = t.data[p].r;
					tb.data[q].d = t.data[p].d;//元素值传递
					q++;						//下一个data
				}
		}
	}
}

//两个稀疏矩阵相加后对应的三元组
void MatAdd(TSMatrix a, TSMatrix b, TSMatrix &c)
{
	if(a.row != b.row || a.cols != b.cols)//判断是否符合矩阵相加条件，即两矩阵行数和列数分别相等
	{
		printf("矩阵相加操作失败\n");
		return;
	}
	c.row = a.row;						//总行数赋值
	c.cols = a.cols;					//总列数赋值
	int i = 0 , j = 0, k = 0;
	while(i < a.nums || j < b.nums)		//遍历两个三元组
	{
		if(a.data[i].r < b.data[j].r)//比较非零数值所在的行数大小，将较小的行数的非零数值放进c的三元组
		{
			c.data[k].r = a.data[i].r;
			c.data[k].c = a.data[i].c;
			c.data[k].d = a.data[i].d;
			i++;
			k++;
		}
		else if(a.data[i].r == b.data[j].r)//比较非零数值所在的行数大小，相等时
		{
			if(a.data[i].c < b.data[j].c)//比较非零数值所在的列数大小，将较小的列数非零数值放进c的三元组
			{
				c.data[k].r = a.data[i].r;
				c.data[k].c = a.data[i].c;
				c.data[k].d = a.data[i].d;
				i++;
				k++;
			}
			else if(a.data[i].c == b.data[j].c)//比较非零数值所在的列数大小，将两个非零元素相加的值放进c的三元组
			{
				c.data[k].r = b.data[j].r;
				c.data[k].c = b.data[j].c;
				c.data[k].d = a.data[i].d + b.data[j].d;
				i++;
				j++;
				k++;
			}
			else							//比较非零数值所在的列数大小，将较小的列数非零数值放进c的三元组
			{
				c.data[k].r = b.data[j].r;
				c.data[k].c = b.data[j].c;
				c.data[k].d = b.data[j].d;
				j++;
				k++;
			}
		}
		else							//比较非零数值所在的行数大小，将较小的行数数非零数值放进c的三元组
		{
			c.data[k].r = b.data[j].r;
			c.data[k].c = b.data[j].c;
			c.data[k].d = b.data[j].d;
			j++;
			k++;
		}
	}
	c.nums = k;//非零元素个数
}

//返回三元组 t 表示的 A[i][j]值
int getvalue(TSMatrix t,int i,int j)
{
	for(int k = 0; k < t.nums; k++)
	{
		if(t.data[k].r == i && t.data[k].c == j)
			return t.data[k].d;
	}
	return 0;
}

//两个稀疏矩阵相乘后对应的三元组
void MatMul(TSMatrix a,TSMatrix b,TSMatrix &c)
{
	if(a.cols != b.row)									//判断是否满足两矩阵相乘的条件，即第一个矩阵的列数与第二矩阵的行数相等
	{
		printf("矩阵相乘操作失败\n");
		return;
	}
	int i, j, k = 0, s;
	c.row = a.row;
	c.cols = b.cols;
	
	for(i = 0; i < a.row; i++)							//控制行数
	{
		for(j = 0; j < b.cols; j++)						//控制列数
		{
			s = 0;
			for(int m = 0; m < b.cols; m++)
			{
				s = s + getvalue(a, m, i)*getvalue(b, j, m);//第一个矩阵行的每个元素与第二个矩阵列的每个元素相乘，并将结果相加
			}
			if(s != 0)										//如果数据元素不为0，则将其放进c三元组中
			{
				c.data[k].r = i;
				c.data[k].c = j;
				c.data[k].d = s;
				k++;
			}
		}
	}
	c.nums = k;												//总非零元素个数
}

int main()
{
	TSMatrix t1, t2, c;			//t1, t2为三元组
	elem a[4][4] = {
		{1,0,3,0},
		{0,1,0,0},
		{0,0,1,0},
		{0,0,1,1}};
	CreatMat(t1, a);			//生成稀疏矩阵A三元组
	printf("a的三元组:\n");
	DipMat(t1);					//输出三元组
	elem b[4][4] = {
		{3,0,0,0},
		{0,4,0,0},
		{0,0,1,0},
		{0,0,0,2}};
	CreatMat(t2, b);			//生成稀疏矩阵B三元组
	printf("b的三元组:\n");
	DipMat(t2);					//输出三元组
	TranTat(t1, c);				//三元组转置
	printf("a转置后\n");
	DipMat(c);					//输出三元组
	printf("c = a + b\nc的三元组:\n");
	MatAdd(t1, t2, c);			//计算两个稀疏矩阵相加后对应的三元组
	DipMat(c);					//输出三元组
	printf("c = a * b\nc的三元组:\n");
	MatMul(t1, t2, c);			//矩阵相乘
	DipMat(c);					//输出三元组
	return 0;
}
